#pragma once
#include "qlib/all.h"
#include <KDTree/KDTree.hpp>
#include "components.h"
#include "models.h"
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include "../layer_ref/models.h"
#include "../../undoRedo/undoRedo.hpp"
#include "../../layout/layout.hpp"
namespace qbe::editing::Extension {

struct PartCheckedInfo {
  std::vector<int> indexs;
  std::vector<qlib::Vec2d> key_points;
  entt::entity node = entt::null;
  bool is_ellipse = false;
  PartCheckedInfo() {}
  PartCheckedInfo(std::vector<int> _indexs, entt::entity node) : indexs(_indexs), node(node) {}
};

struct ExtendLine {
  entt::entity entity;
  qlib::Path::s_ptr node;                 //延长的线
  std::vector<std::vector<int>> indexes;  //延长线段的索引
  std::vector<qlib::Vec2d> hit_points;    //和延长线段的交点
  ExtendLine(entt::entity& _entity, qlib::Path::s_ptr _node, std::vector<std::vector<int>> _indexes, std::vector<qlib::Vec2d> _hit_points)
      : entity(_entity), node(_node), indexes(_indexes), hit_points(_hit_points) {}
};

struct ExtensionInfo {
  int line_num;        //线段编号0开始
  int md_index;        //延长端的索引
  qlib::Vec2d md_pos;  //延长后的坐标
  ExtensionInfo(int _line_num, int _md_index, qlib::Vec2d _md_pos) : line_num(_line_num), md_index(_md_index), md_pos(_md_pos) {}
};

double distance(qlib::Vec2d a, qlib::Vec2d b);

qlib::Vec2d normalizeVector(qlib::Vec2d pt);

qlib::Vec2d transOutPoint(qlib::Vec2d& p, LayerRef::LayerModel& levelParam);

bool rayIntersectsAABB2D(qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, qlib::Vec2d& min, qlib::Vec2d& max);


// 求两个向量的叉积
double cross_product(const qlib::Vec2d& p1, const qlib::Vec2d& p2);

// 计算两条线段的交点
bool computeIntersection(const qlib::Vec2d& A, const qlib::Vec2d& B, const qlib::Vec2d& C, const qlib::Vec2d& D, qlib::Vec2d& intersection);


std::vector<entt::entity> getQueryEntities(std::vector<qbe::layout::CellQuad::Node>& nodes);

std::vector<ExtendLine> getPreExtendNodes(layout::LayoutCmd& layout_cmd, qlib::Cell::s_ptr current_cell, qlib::Vec2d mouse_pos, PartCheckedInfo& pre_extend_line,
                                          qlib::Path::s_ptr mouse_line, LayerRef::LayerModel& levelparam);

bool pointIsInsideScreen(qlib::Vec2d& point, LayerRef::LayerModel& levelParam, std::vector<double> screen_box);

void computeRayBoundingBox(qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, qlib::Vec2d& min, qlib::Vec2d& max, std::vector<double> screen_box);

double getRayToLineSegmentDist(qlib::Vec2d& rayOrigin, qlib::Vec2d& rayDirection, qlib::Vec2d& point1, qlib::Vec2d& point2);

std::vector<qlib::Vec2d> getEntityBoundingBox(qlib::Cell::s_ptr current_cell, entt::entity el);

std::vector<entt::entity> getIntersectNodes(layout::LayoutCmd& layout_cmd, qlib::Cell::s_ptr current_cell, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, qlib::Vec2d& ray_dir_global,
                                            LayerRef::LayerModel& levelParam, std::vector<double> screen_box);

bool isValidInsNode(entt::entity el);

bool elementIsVisible(long layer_num);

void intersectWithPath(qlib::Path::s_ptr target_path, qlib::Path::s_ptr path, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, int start_index,
                       int end_index, double& line_length, std::vector<qlib::Vec2d>& all_intersections, std::vector<int>& sel_indexs);

void intersectWithPolygon(qlib::Polygon::s_ptr polygon, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, double& line_length,
                          std::vector<qlib::Vec2d>& all_intersections, std::vector<int>& sel_indexs);

void intersectWithRefer(qlib::Path::s_ptr target_path, qlib::Reference::s_ptr refer, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, int start_index,
                        int end_index, double& line_length, std::vector<qlib::Vec2d>& all_intersections);
void intersectWithKeyPoint(qlib::Path::s_ptr target_path, qlib::KeyPoint::s_ptr kp, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir, int start_index,
                        int end_index, double& line_length, std::vector<qlib::Vec2d>& all_intersections);
qlib::Polygon::s_ptr getPolygon(qlib::Cell::s_ptr current_cell, entt::entity el_nod);

void intersectWithAll(layout::LayoutCmd& layout_cmd, qlib::Cell::s_ptr current_cell, qlib::Path::s_ptr target_path, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir,
                      qlib::Vec2d& ray_dir_global, int& start_index, int& end_index, double& line_length, std::vector<qlib::Vec2d>& all_intersections,
                      LayerRef::LayerModel& levelParam, std::vector<double> screen_box);

void intersectWithPickedElements(qlib::Cell::s_ptr current_cell, qlib::Path::s_ptr target_path, qlib::Vec2d& ray_start, qlib::Vec2d& ray_dir,
                                 int& start_index, int& end_index, double& line_length, std::vector<qlib::Vec2d>& all_intersections,
                                 std::vector<entt::entity>& overall_selected_nodes, std::vector<entt::entity>& part_selected_nodes);

bool elementIsSelected(qlib::Cell::s_ptr current_cell, qlib::Path::s_ptr target, std::vector<entt::entity>& overall_selected_nodes);
//执行最终延申线操作修改数据
void extendPath(qlib::Cell::s_ptr current_cell, entt::entity& path_entity, qlib::Path::s_ptr path_node, std::vector<ExtensionInfo>& extend_data, bool selected, undoRedoT::UndoRedoModule& undoRedoModule, layout::LayoutCmd& layout_cmd, ExtensionModel& param);

void doExtendLine(layout::LayoutCmd& layout_cmd, entt::entity& path_entity, qlib::Path::s_ptr path_node, std::vector<std::vector<int>>& picked_lines_index, std::vector<qlib::Vec2d>& hit_points,
                  qlib::Cell::s_ptr current_cell, std::vector<qlib::Vec2d>& extend_inters, std::vector<std::vector<qlib::Vec2d>>& extend_lines,
                  bool& data_changed, bool process_extend, LayerRef::LayerModel& levelParam, std::vector<entt::entity>& overall_selected_nodes,
                  std::vector<PartCheckedInfo>& part_selected_nodes, std::vector<double> screen_box, undoRedoT::UndoRedoModule undoRedoModule, ExtensionModel& param);
void updateDisplayIntersAndLines(std::vector<qlib::Vec2d> points, std::vector<std::vector<qlib::Vec2d>> lines, qbe::layout::CellCmd& cmd,
                                 layout::CellState& cell_state);

void clearExtensionDisplay(entt::entity& entity, qbe::layout::CellCmd& cmd, layout::CellState& cell_state);

//更新左下角信息 选中了要延申的线 是否存在交点
void updateExtensionStatusBarInfo(ecs::Bus& bus, bool picked_lines, bool no_inter_poin, bool exist = false);

double distancePointToSegment(const qlib::Vec2d& Q, const qlib::Vec2d& P1, const qlib::Vec2d& P2);

std::vector<qlib::Vec2d> filterDuplicatesPoints(const std::vector<qlib::Vec2d>& points);
}